home *** CD-ROM | disk | FTP | other *** search
/ 17 Bit Software 5: The Fifth Dimension / 17 Bit - The Fifth Dimension (1995)(17 Bit Software)[!].iso / files / 3592.dms / 3592.adf / JPEGAGAS.LHA / jpegAGAsrc / ppm2AGA / ppm2ilbm.c < prev    next >
C/C++ Source or Header  |  1995-01-07  |  31KB  |  998 lines

  1. /* ppm2ilbm module                 */
  2. /* written by Günther Röhrich      */
  3. /* this is version 1.5             */
  4.  
  5. /* this code is tested with Aztec C 5.2a and GNU C 2.5.8 */
  6. /* NOTE: you will need the newiff V37 or higher package */
  7. /* (V37 is available on Fish-disk 705) */
  8.  
  9.  
  10. #include <clib/exec_protos.h>
  11. #include <libraries/iffparse.h>
  12. #include <dos/dos.h>
  13. #include <iffp/ilbmapp.h>
  14. #include <iffp/packer.h>
  15. #include <stdio.h>
  16. #include <graphics/modeid.h>
  17.  
  18. #include "ppm2AGA.h"
  19.  
  20. #ifndef __GNUC__
  21. #include <pragmas/exec_pragmas.h>
  22. #include <pragmas/iffparse_pragmas.h>
  23. #endif
  24.  
  25.  
  26.  
  27. /* needed when compiling with newiff V37 package */
  28. /* (not needed with V39 or higher) */
  29.  
  30. #ifndef BMHDF_CMAPOK
  31. #define BMHDF_CMAPOK (1 << 7)
  32. #endif
  33.  
  34.  
  35. /* externals used by this module */
  36.  
  37.  
  38. extern int AbortCheck(void);
  39. extern void PLProgress(ULONG Value, ULONG MaxValue);
  40. extern volatile unsigned short MaxError, MaxErrorPos;
  41. extern void EncodeHAM(UBYTE *yorig, UBYTE *yham, char *ColorTable, 
  42.                        short NumColors, short xsize);
  43. extern int MapColorASM(colorhist_vector colormap, pixval r1, pixval g1, pixval b1, 
  44.              int NumColors);
  45. extern int ExactColor;
  46. extern int GfxEnable;
  47. extern int VGAenable;
  48. extern int jpegAGA;
  49. extern char *ILBMfile;
  50. extern char *BaseName;
  51. extern ULONG SMR;
  52. extern ULONG SMR_DisplayID;
  53.  
  54. /* definitions for the display routines */
  55.  
  56. extern int InitDisplay(int cols, int rows, ULONG Mode, int NumPlanes);
  57. extern void SetDisplayColor(int ColorNumber, UBYTE r, UBYTE g, UBYTE b);
  58. extern void DisplayRow(char *array, int cols, int row);
  59. extern void CloseDisplay(void);
  60.  
  61. /* globals defined in this module */
  62.  
  63. #ifdef DEBUG_ASM
  64. int MapColor(colorhist_vector colormap, pixval r1, pixval g1, pixval b1, 
  65.              int NumColors);
  66. #endif
  67.  
  68. unsigned short Mult_Table[2*256];
  69. unsigned long  Mult_Table32[2*256];
  70. jmp_buf ErrorEnv;
  71. int cols, rows, rowcnt;
  72. pixel **pixels;
  73. pixel *pixrow;
  74. pixval maxval;
  75. int ppmformat;
  76. char ColorTable[64*3] = {0};
  77. int ColorRegMax; 
  78. unsigned short ConvertMode;
  79. char *ColorCache; /* a 256K cache for EncodeHAM() */
  80.  
  81. /* these are needed by Floyd-Steinberg-routines */
  82. long  *thisrerr;
  83. long  *nextrerr;
  84. long  *thisgerr;
  85. long  *nextgerr;
  86. long  *thisberr; 
  87. long  *nextberr;     
  88. extern int floyd; 
  89. int fs_direction = 1;
  90. int Convert4096;
  91. int Convert262144;
  92. #define FS_SCALE 1024
  93.  
  94. /* locals defined in this module */
  95.  
  96. static FILE *fppm;
  97. static FILE *ColorMapFile;
  98. static struct IFFHandle *iff;
  99. static struct ILBMInfo ilbm;
  100. static int error;
  101. static LONG IFFError;
  102. static unsigned char *coded_rowbuf;
  103. static unsigned char *hamarray;
  104. static int returnvalue;
  105. static void ppmCleanUp(void);
  106. static int readall;
  107. static colorhist_vector chv, colormap;
  108. static BYTE *CompressBuffer;
  109. static void encode_row(UBYTE *row, int cols, int nPlanes);
  110. static int ColorShift, NumColors;
  111. static gray *pgmrow;
  112.  
  113. static int lumcompare(colorhist_vector ch1, colorhist_vector ch2)
  114. {
  115.  return (int)((double)PPM_LUMIN(ch1->color) - (double)PPM_LUMIN(ch2->color));
  116. }
  117.  
  118.  
  119. int ppm2ilbm(char *PPMfile, ULONG Mode, int NumPlanes, ULONG MaxMem)
  120. {
  121.  int i, colors;
  122.  pixel *pP;
  123.  unsigned short AbsMaxError = 0;
  124.  unsigned short MaxErrorXPos = 0;
  125.  unsigned short MaxErrorYPos = 0;
  126.  
  127.  /* initialize everything                            */
  128.  /* this is needed because we may call this function */
  129.  /* multiple times                                   */
  130.  returnvalue = 0;
  131.  fppm = NULL;
  132.  ColorMapFile = NULL;
  133.  readall = 0;
  134.  pixrow = NULL;
  135.  pixels = NULL;
  136.  hamarray = NULL; coded_rowbuf = NULL; ColorCache=NULL; 
  137.  memset(&ilbm, 0, sizeof(struct ILBMInfo)); 
  138.  chv = NULL;
  139.  colormap = NULL;
  140.  CompressBuffer = NULL;
  141.  pgmrow = NULL;
  142.  
  143.  
  144.  /* multiplication table is needed by assembler subroutines */
  145.  for(i=-255; i<256; i++)
  146.  {
  147.    Mult_Table[i+255] = i*i;
  148.    Mult_Table32[i+255] = i*i;
  149.  }
  150.  
  151.  
  152.  /* if we encounter an error we longjmp() to this location       */
  153.  /* the ppmCleanUp() function will free all resources  allocated */
  154.  /* in this module                                               */
  155.  
  156.  error = setjmp(ErrorEnv);
  157.  if(error != 0) 
  158.  {
  159.   ppmCleanUp();
  160.   return error;
  161.  }  
  162.  
  163.  
  164.  /* try to open the ppm file */
  165.  fppm = fopen(PPMfile, "r");
  166.  if(!fppm) pm_error("Could not open file %s\n", PPMfile);
  167.  
  168.  /* read the header of the ppm file */
  169.  ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat); 
  170.  
  171.  #ifdef DEBUG
  172.  pm_message("Cols: %d, Rows: %d, MaxVal: %d, Format: %d\n",
  173.              cols, rows, maxval, ppmformat);
  174.  #else
  175.  pm_message("Cols: %d, Rows: %d, MaxVal: %d\n", cols, rows, maxval);
  176.  #endif
  177.  
  178.  /* Initialize Floyd-Steinberg error vectors. */
  179.  thisrerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  180.  nextrerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  181.  thisgerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  182.  nextgerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  183.  thisberr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  184.  nextberr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  185.  srandom( (int) ( time( 0 ) ^ getpid(0) ) );
  186.  for ( i = 0; i < cols + 2; ++i )
  187.  {
  188.    thisrerr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  189.    thisgerr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  190.    thisberr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  191.    /* (random errors in [-1 .. 1]) */ 
  192.  }
  193.  
  194.  /* try to open the output file */
  195.  
  196.  if(!jpegAGA)
  197.  {
  198.    if(!(ilbm.ParseInfo.iff = AllocIFF()))
  199.      pm_error("Could not do AllocIFF()");
  200.  
  201.    iff = ilbm.ParseInfo.iff;
  202.  
  203.    IFFError = openifile((struct ParseInfo *)&ilbm, (UBYTE *)ILBMfile, IFFF_WRITE);
  204.    if(IFFError) pm_error(""); /* openifile() will print error messages... */
  205.  }
  206.  
  207.  if(Mode == HAM8 || Mode == HAM6 || Mode == COLORMAP)
  208.  {
  209.    int Clustering;
  210.    if(Mode == HAM8)
  211.    {
  212.      NumColors = NumPlanes;
  213.      ColorRegMax  = 63;
  214.      ColorShift   = 2; /* we only have 256K colors */
  215.      NumPlanes    = 8;
  216.      ConvertMode  = 1; /* Needed by EncodeHAM() */
  217.      Clustering   = 0;
  218.      Convert4096  = 0; /* No 4096-FS conversion */
  219.      if(floyd) Convert262144 = 1; /* 262144 conversion */
  220.     
  221.    }
  222.    else if(Mode == HAM6)
  223.    {
  224.      NumColors = NumPlanes;
  225.      ColorRegMax = 15; 
  226.      ColorShift  = 4; /* converting to 4096 colors will be done by FS dithering */
  227.      NumPlanes   = 6;
  228.      ConvertMode = 0; /* Needed by EncodeHAM() */
  229.      Clustering  = 0;
  230.      if(floyd)
  231.        Convert4096 = 1; /* Do 4096-FS conversion */
  232.      Convert262144 = 0;
  233.    }
  234.    else /* COLORMAP */
  235.    { 
  236.      NumColors = 1 << NumPlanes;      
  237.      ColorRegMax = 255;
  238.      ColorShift = 0; /* we will handle full 16M colors */
  239.      if(ppmformat == PGM_FORMAT || ppmformat == RPGM_FORMAT || ExactColor == 1)
  240.      {
  241.        Clustering = 0;
  242.      }
  243.      else
  244.      {
  245.        Clustering = 2;
  246.      }
  247.      Convert4096 = 0; /* No 4096-FS conversion */
  248.      Convert262144 = 0;
  249.    } 
  250.        
  251.    if( cols*rows*3 <= (int)MaxMem)
  252.    {     
  253.      /* read the complete picture into memory */
  254.      int row;
  255.      readall = 1;
  256.      pm_message("Reading complete picture into memory...\n");
  257.      pixels = ppm_allocarray(cols, rows);     
  258.      for(row = 0; row < rows; ++row)
  259.      {
  260.        if(AbortCheck()) pm_error("^C\n");
  261.        ppm_readppmrow(fppm, pixels[row], cols, maxval, ppmformat);
  262.        if(maxval != ColorRegMax)
  263.        {
  264.          if(maxval == 255)
  265.          {
  266.            for(i=0, pP=pixels[row]; i < cols; ++i, ++pP)
  267.            {
  268.              pP->r = pP->r >> ColorShift;
  269.              pP->g = pP->g >> ColorShift;
  270.              pP->b = pP->b >> ColorShift;
  271.            }
  272.          }
  273.          else
  274.          {
  275.            for(i=0, pP=pixels[row]; i < cols; ++i, ++pP)
  276.              PPM_DEPTH(*pP, *pP, maxval, ColorRegMax);
  277.          }
  278.        }
  279.      }
  280.    }
  281.    else
  282.    {
  283.      rowcnt = 0;
  284.      if(!(pixrow = ppm_allocrow(cols)))
  285.        pm_error("Out of memory.\n");     
  286.     }
  287.  
  288.  
  289.    /* allocate enough room for one row of chunky HAM pixels  */
  290.    /* (this array will also be used for colormap conversion) */
  291.    if(!(hamarray = malloc(RowBits(cols))))
  292.      pm_error("Out of memory.\n");
  293.  
  294.    /* we only have to clear the space between cols and RowBits(cols)    */
  295.    /* hamarray will be larger in most cases because of special alignment*/
  296.    for(i = cols; i < RowBits(cols); i++) hamarray[i] = 0;
  297.    pm_message("Computing colormap...\n");
  298.  
  299.  
  300.    /* now we make a histogram of the picture...          */
  301.    /* if we increase Clustering we will find less colors */
  302.    /* we allow a maximum of 10000 colors                 */
  303.    /* ColorShift is the shift needed for HAM encoding    */
  304.    for(i=Clustering; i<5; i++)
  305.    {
  306.      if((chv = ppm_fcomputecolorhist(fppm, cols, rows, 10000, &colors, ColorShift, i)))
  307.        break;
  308.      if(AbortCheck()) pm_error("^C\n");
  309.      pm_message("Could not compute colormap, trying again...\n");
  310.      rowcnt=0;
  311.      if(!readall)
  312.      { 
  313.        rewind(fppm); /* re-initialise the ppm pointers for reading again */
  314.        ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);       
  315.      }
  316.    } 
  317.  
  318.    pm_message("Found %d colors.\n", colors);
  319.  
  320.  
  321.    /* now we try to find a suitable colormap... */
  322.    colormap = mediancut(chv, colors, rows*cols, ColorRegMax, NumColors);
  323.    ppm_freecolorhist(chv); /* we don't need the histogram any more */
  324.    chv = NULL;
  325.    /* sort the colors in ascending luminance order...  */ 
  326.    /* (the first color will be the background color)      */
  327.    if(NumColors < colors)
  328.    {
  329.      qsort((char *)colormap, NumColors, sizeof(struct colorhist_item), lumcompare);
  330.    }
  331.    else
  332.    {
  333.      qsort((char *)colormap, colors, sizeof(struct colorhist_item), lumcompare);
  334.    }
  335.  
  336.    
  337.    if(!jpegAGA)
  338.    {   
  339.      /* the CompressBuffer is needed by the cmpByteRun1 compressor */
  340.      if(!(CompressBuffer = malloc(MaxPackedSize(RowBytes(cols)))))
  341.        pm_error("Out of memory allocating the compress buffer.\n");
  342.  
  343.      /* the ColorCache is needed by EncodeHAM() for higher speed */
  344.      /* (for HAM6 encoding only 4097 bytes are needed...)        */
  345.      if(!(ColorCache = malloc(262145)))
  346.        pm_error("Out of memory allocating the color cache.\n");
  347.  
  348.      /* the coded_rowbuf is needed by the IFF encoder */
  349.      if(!(coded_rowbuf = (unsigned char *)malloc(RowBytes(cols))))
  350.        pm_error("Out of memory allocating coded_rowbuf.\n");
  351.      for(i=RowBytes(cols)-1; i>=0; i--) coded_rowbuf[i]=0;
  352.  
  353.      /* write the FORM chunk */
  354.      IFFError = PushChunk(iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN);
  355.      if(IFFError) pm_error("Error writing FORM chunk.\n");
  356.      
  357.      /* initialize the BMHD chunk */
  358.      ilbm.Bmhd.w = cols;
  359.      ilbm.Bmhd.h = rows;             /* Width, height in pixels */
  360.      ilbm.Bmhd.x = 0;
  361.      ilbm.Bmhd.y = 0;                /* x, y position for this bitmap  */
  362.      ilbm.Bmhd.nPlanes = NumPlanes;  /* # of planes (not including mask) */
  363.      ilbm.Bmhd.masking = mskNone;   
  364.      ilbm.Bmhd.compression = cmpByteRun1;   
  365.      ilbm.Bmhd.flags = BMHDF_CMAPOK;  /* CMAP has 8 significant bits */
  366.      ilbm.Bmhd.transparentColor = 0; 
  367.      ilbm.Bmhd.xAspect = cols;         
  368.      ilbm.Bmhd.yAspect = rows;       /* xAspect, yAspect */
  369.      ilbm.Bmhd.pageWidth = cols;
  370.      ilbm.Bmhd.pageHeight = rows;    /* pageWidth, pageHeight */
  371.   
  372.      /* write the BMHD chunk */   
  373.      IFFError = putbmhd(iff, &ilbm.Bmhd);
  374.      if(IFFError) pm_error("Error writing BMHD chunk.\n");
  375.   
  376.      if(GfxEnable) InitDisplay(cols, rows, Mode, NumPlanes);
  377.    }
  378.    
  379.    if(Mode == HAM8 || Mode == HAM6)
  380.    { 
  381.      /* fill in the ColorTable in B R G order */
  382.      /* (this is better for HAM encoding)     */       
  383.      for(i=0; i<NumColors; i++)
  384.      {
  385.        ColorTable[i*3]   = PPM_GETB(colormap[i].color);
  386.        ColorTable[i*3+1] = PPM_GETR(colormap[i].color);
  387.        ColorTable[i*3+2] = PPM_GETG(colormap[i].color);
  388.        if(!jpegAGA)
  389.        {
  390.          if(ColorShift == 4)
  391.            SetDisplayColor(i, (PPM_GETR(colormap[i].color) << ColorShift) | 
  392.                                PPM_GETR(colormap[i].color),
  393.                               (PPM_GETG(colormap[i].color) << ColorShift) |
  394.                                PPM_GETG(colormap[i].color),
  395.                               (PPM_GETB(colormap[i].color) << ColorShift) |
  396.                                PPM_GETB(colormap[i].color));
  397.          else
  398.           SetDisplayColor(i, (PPM_GETR(colormap[i].color) << ColorShift),
  399.                              (PPM_GETG(colormap[i].color) << ColorShift),
  400.                              (PPM_GETB(colormap[i].color) << ColorShift));
  401.        }
  402.      }
  403.      free(colormap); /* we don't need the colormap any more */
  404.      colormap = NULL;
  405.  
  406.      if(jpegAGA)
  407.      {
  408.        char *MapDir;
  409.        unsigned short MagicNumber = 0x1203; /* guess what this means! */
  410.        int Reserved=0; 
  411.        unsigned char color;
  412.        MapDir = getenv("MAPDIR");  
  413.  
  414.        ColorMapFile = fopen(ILBMfile, "w");
  415.        
  416.        if(!ColorMapFile && !BaseName)
  417.        {
  418.          if(MapDir)
  419.           if(strlen(MapDir) != 0)
  420.          {
  421.            char *MapDirName;
  422.            int pos,i;
  423.            MapDirName = malloc(strlen(MapDir)+strlen(ILBMfile)+5); /* worst case */
  424.            if(!MapDirName) pm_error("Out of memory.\n");
  425.            strcpy(MapDirName, MapDir);
  426.  
  427.            i = strlen(MapDirName);
  428.            if(MapDirName[i-1] != '/' && MapDirName[i-1] != ':')
  429.            {
  430.              strcat(MapDirName, "/");
  431.              i++;
  432.            }
  433.            i = strlen(ILBMfile);
  434.            while(i > 0 && ILBMfile[i-1] != '/' && ILBMfile[i-1] != ':') i--;
  435.            strcat(MapDirName, &ILBMfile[i]);
  436.            ColorMapFile = fopen(MapDirName, "w");
  437.            if(ColorMapFile) pm_message("Writing mapfile: %s\n", MapDirName);
  438.          }
  439.        }
  440.        else if(!ColorMapFile && BaseName && MapDir)
  441.          if(strlen(MapDir) != 0)
  442.        {
  443.          char *NewName;
  444.          int i;
  445.          NewName = malloc(strlen(MapDir)+strlen(BaseName)+strlen(ILBMfile)); /* worst case */
  446.          if(!NewName) pm_error("Out of memory.\n");
  447.          strcpy(NewName, MapDir);
  448.          i=strlen(NewName);
  449.          if(NewName[i-1] != '/' && NewName[i-1] != ':')
  450.          {
  451.            strcat(NewName, "/");
  452.            i++;
  453.          }
  454.          strcat(NewName, BaseName);
  455.          i=strlen(ILBMfile);
  456.          while(i > 0 && ILBMfile[i-1] != '/' && ILBMfile[i-1] != ':') i--;
  457.          if(strlen(ILBMfile) > i+3)
  458.          {
  459.            strcat(NewName, &ILBMfile[i+3]);
  460.            i = strlen(NewName) - 4;
  461.            if(i < 1) pm_error("Wrong mapfile name.\n");
  462.            while(i > 0 && NewName[i-1] != '.') i--;
  463.            if(NewName[i-1] == '.')
  464.            {
  465.              strcpy(&NewName[i], "map");
  466.              printf("%s\n", NewName);
  467.              ColorMapFile = fopen(NewName, "w");
  468.            }
  469.          }
  470.          free(NewName);
  471.        }
  472.          
  473.  
  474.        if(!ColorMapFile) pm_error("Could not open color map file for jpegAGA.\n");
  475.  
  476.        if(fwrite(&MagicNumber, 2, 1, ColorMapFile) != 1) pm_error("Write error.\n");
  477.        if(fwrite(&Reserved,    4, 1, ColorMapFile) != 1) pm_error("Write error.\n");     
  478.        if(fwrite(ColorTable,  64*3, 1, ColorMapFile) != 1) pm_error("Write error.\n");
  479.        pm_message("Colormap file for jpegAGA/PhotoCDAGA created.\n");
  480.        ppmCleanUp();
  481.        return 0;
  482.      }
  483.  
  484.      memset(ColorCache, 0, 262145); /* clear the color cache */          
  485.  
  486.      do
  487.      {
  488.        int y;
  489.        rowcnt=0;
  490.        
  491.        /* if we don't need an additional color the color cache */
  492.        /* will remain valid and should not be cleared          */
  493.  
  494.        memset(ColorCache, 0, 262145); /* clear the color cache */
  495.    
  496.  
  497.        if(!readall)
  498.        {
  499.          rewind(fppm);
  500.          ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);
  501.        }
  502.  
  503.        /* if we have all colors we can write the CMAP chunk */
  504.        if(NumColors == ColorRegMax+1)
  505.        {
  506.          IFFError = PushChunk(iff, 0, ID_CMAP, (ColorRegMax+1)*3);
  507.          if(IFFError) pm_error("Error writing CMAP header.\n");
  508.  
  509.          for( i = 0; i <= ColorRegMax; i++) 
  510.          {
  511.            ColorRegister cmapReg;
  512.            if(ColorShift == 4) /* HAM6 */
  513.            {
  514.              cmapReg.red   = (ColorTable[i*3+1] << ColorShift)
  515.                              | ColorTable[i*3+1];   /* red */
  516.              cmapReg.green = (ColorTable[i*3+2] << ColorShift)
  517.                              | ColorTable[i*3+2];   /* green */
  518.              cmapReg.blue  = (ColorTable[i*3]   << ColorShift)
  519.                              | ColorTable[i*3];   /* blue */
  520.            }
  521.            else /* HAM8 */
  522.            {
  523.              cmapReg.red   = ColorTable[i*3+1] << ColorShift;   /* red */
  524.              cmapReg.green = ColorTable[i*3+2] << ColorShift;   /* green */
  525.              cmapReg.blue  = ColorTable[i*3]   << ColorShift;   /* blue */ 
  526.            }
  527.            IFFError = WriteChunkBytes(iff, (UBYTE *)&cmapReg, 3);
  528.            if(IFFError!=3) pm_error("Error writing CMAP chunk.\n");
  529.          }
  530.          IFFError = PopChunk(iff); /* close CMAP */
  531.          if(IFFError) pm_error("Error closing CMAP.\n");
  532.  
  533.          /* write the CAMG chunk */
  534.          if(SMR)
  535.          {
  536.            ilbm.camg = SMR_DisplayID;
  537.          }
  538.          else
  539.          {
  540.            if(VGAenable)
  541.            {
  542.              if(cols > 370 || rows > 260)
  543.              {
  544.                ilbm.camg = VGAPRODUCTHAM_KEY;
  545.              }
  546.              else
  547.              {
  548.                ilbm.camg = VGALORESHAMDBL_KEY;
  549.              }
  550.            }
  551.            else
  552.            {
  553.              ilbm.camg = HAM;
  554.              if(cols > 370) ilbm.camg = ilbm.camg | HIRES;
  555.              if(rows > 280) ilbm.camg = ilbm.camg | LACE;
  556.            }
  557.          }
  558.          IFFError = putcamg(iff, &ilbm.camg);
  559.          if(IFFError) pm_error("Error writing CAMG chunk.\n");
  560.  
  561.          /* start with the BODY chunk */
  562.          IFFError = PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
  563.          if(IFFError) pm_error("Error writing BODY header.\n");
  564.        }
  565.  
  566.        /* set a dummy value for AbsMaxError                          */
  567.        /* it will contain the maximum error for the complete picture */ 
  568.        AbsMaxError=0;
  569.   
  570.        for(y=0; y<rows; y++)
  571.        {
  572.          pixel *nextrow;          
  573.  
  574.          MaxError = 0;         
  575.            
  576.          nextrow = next_pixrow(fppm, y, ColorShift);
  577.           
  578.          if(AbortCheck()) pm_error("^C\n");
  579.  
  580.          EncodeHAM(nextrow, hamarray, ColorTable, NumColors*3, (short)cols);
  581.  
  582.          
  583.          /* remember the color of the pixel with the maximum error */
  584.          /* even if MaxError == 0 we will get a valid entry in the */
  585.          /* colormap but it will not be used by the picture        */           
  586.          if(MaxError > AbsMaxError)
  587.          {
  588.            MaxErrorXPos = MaxErrorPos;
  589.            MaxErrorYPos = y;
  590.            AbsMaxError = MaxError;
  591.  
  592.            /* use the color of the pixel with the maximum error as */
  593.            /* a ColorTable entry                                   */
  594.            /* we will have to recompute the picture if we want to  */
  595.            /* use the additional color                             */
  596.            if(NumColors <= ColorRegMax)
  597.            {
  598.              ColorTable[NumColors*3]   = PPM_GETB(pixrow[MaxErrorXPos]);
  599.              ColorTable[NumColors*3+1] = PPM_GETR(pixrow[MaxErrorXPos]);
  600.              ColorTable[NumColors*3+2] = PPM_GETG(pixrow[MaxErrorXPos]);
  601.            }        
  602.          }
  603.  
  604.          /* if all colors are set we can write our row to the BODY chunk */
  605.          if(NumColors == ColorRegMax+1) 
  606.          {
  607.            encode_row(hamarray, cols, NumPlanes);
  608.          }
  609.          DisplayRow(hamarray, cols, y);
  610.        }
  611.  
  612.        /* this is only for debugging purposes */
  613.        if(NumColors <= ColorRegMax)
  614.        {
  615.          #ifdef DEBUG
  616.          pm_message("Max Error: %hd ", AbsMaxError);
  617.          #endif
  618.          if(AbsMaxError == 0)
  619.          {
  620.            printf("\n");
  621.          }
  622.          else
  623.          {
  624.            #ifdef DEBUG
  625.            pm_message("Color %hd, XPos: %hd, YPos: %hd\n", NumColors, MaxErrorXPos, MaxErrorYPos);
  626.            #endif
  627.          }
  628.        }
  629.        SetDisplayColor(NumColors, ColorTable[NumColors*3+1] << ColorShift,
  630.                                   ColorTable[NumColors*3+2] << ColorShift,
  631.                                   ColorTable[NumColors*3]   << ColorShift);
  632.        NumColors = NumColors + 1; 
  633.     
  634.      /* finish if we have set all colors */
  635.      } while(NumColors <= ColorRegMax+1);
  636.  
  637.  
  638.      #ifdef DEBUG
  639.      pm_message("Max Error: %hd, XOffset: %hd YOffset: %hd\n",
  640.                AbsMaxError, MaxErrorXPos, MaxErrorYPos);
  641.  
  642.      pm_message("Colortable: ");
  643.      for(i=0; i<=ColorRegMax; i++)
  644.      {
  645.        pm_message("%hd,%hd,%hd ",ColorTable[i*3],
  646.                    ColorTable[i*3+1],ColorTable[i*3+2]);
  647.      }
  648.      pm_message("\n");
  649.      #endif
  650.  
  651.      /* close the BODY chunk */
  652.      IFFError = PopChunk(iff); 
  653.      if(IFFError) pm_message("Error closing the BODY chunk.\n");
  654.    }
  655.    
  656.  
  657.    else if(Mode == COLORMAP)
  658.    { 
  659.      /* if floyd is nonzero we will use Floyd-Steinberg dithering */
  660.      int row, fs_direction;
  661.      register int col, limitcol, ind;
  662.      register pixel *pP;
  663.      register long sg, sr, sb, err;
  664.      long *temperr;
  665.  
  666.      /*
  667.      ** map the colors in the image to their closest match in the
  668.      ** new colormap, and write 'em out.
  669.      */
  670.        
  671.      pm_message( "Mapping image to new colors...\n" );
  672.  
  673.      /* write the CMAP chunk */
  674.      IFFError = PushChunk(iff, 0, ID_CMAP, NumColors*3);
  675.      if(IFFError) pm_error("Error writing CMAP header.\n");
  676.      for( i = 0; i < NumColors; i++) 
  677.      {
  678.        ColorRegister cmapReg;
  679.        cmapReg.red   = PPM_GETR( colormap[i].color );   /* red   */
  680.        cmapReg.green = PPM_GETG( colormap[i].color );   /* green */
  681.        cmapReg.blue  = PPM_GETB( colormap[i].color );   /* blue  */
  682.        SetDisplayColor(i, cmapReg.red, cmapReg.green, cmapReg.blue);
  683.        IFFError = WriteChunkBytes(iff, (UBYTE *)&cmapReg, 3);
  684.        if(IFFError!=3) pm_error("Error writing CMAP chunk.\n");
  685.      }
  686.      IFFError = PopChunk(iff); /* close CMAP */
  687.      if(IFFError) pm_error("Error closing CMAP.\n");
  688.  
  689.      /* write the CAMG chunk */
  690.      if(SMR)
  691.      {
  692.        ilbm.camg = SMR_DisplayID;
  693.      }
  694.      else
  695.      {
  696.        ilbm.camg = 0;
  697.        if(VGAenable)
  698.        {
  699.          if(cols > 370 || rows > 260)
  700.            ilbm.camg = VGAPRODUCT_KEY;
  701.          else
  702.            ilbm.camg = VGALORESDBL_KEY;
  703.        }
  704.        else
  705.        {
  706.          if(cols > 370) ilbm.camg = ilbm.camg | HIRES;
  707.          if(rows > 280) ilbm.camg = ilbm.camg | LACE;
  708.        }
  709.      }
  710.      IFFError = putcamg(iff, &ilbm.camg);
  711.      if(IFFError) pm_error("Error writing CAMG chunk.\n");
  712.  
  713.      /* start with the BODY chunk */
  714.      IFFError = PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
  715.      if(IFFError) pm_error("Error writing BODY header.\n");
  716.  
  717.      rowcnt=0;
  718.      if(!readall)
  719.      {
  720.        rewind(fppm);
  721.        ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);       
  722.      }
  723.  
  724.      if ( floyd )
  725.      {
  726.        fs_direction = 1;
  727.      }
  728.      for ( row = 0; row < rows; ++row )
  729.      {
  730.        /* PLProgress(row, rows); */
  731.        if(AbortCheck()) pm_error("^C\n");
  732.        if ( floyd )
  733.          for ( col = 0; col < cols + 2; ++col )
  734.            nextrerr[col] = nextgerr[col] = nextberr[col] = 0;
  735.        if ( ( ! floyd ) || fs_direction )
  736.        {
  737.          col = 0;
  738.          limitcol = cols;
  739.          /* pP = pixels[row]; */
  740.          pP = next_pixrow(fppm, row, ColorShift);
  741.        }
  742.        else
  743.        {
  744.          col = cols - 1;
  745.          limitcol = -1;
  746.          /* pP = &(pixels[row][col]); */
  747.          pP = &(next_pixrow(fppm, row, ColorShift)[col]);
  748.        }
  749.        do
  750.        {
  751.          if ( floyd )
  752.          {
  753.            /* Use Floyd-Steinberg errors to adjust actual color. */
  754.            sr = PPM_GETR(*pP) + thisrerr[col + 1] / FS_SCALE;
  755.            sg = PPM_GETG(*pP) + thisgerr[col + 1] / FS_SCALE;
  756.            sb = PPM_GETB(*pP) + thisberr[col + 1] / FS_SCALE;
  757.            if ( sr < 0 ) sr = 0;
  758.            else if ( sr > maxval ) sr = maxval;
  759.            if ( sg < 0 ) sg = 0;
  760.            else if ( sg > maxval ) sg = maxval;
  761.            if ( sb < 0 ) sb = 0;
  762.            else if ( sb > maxval ) sb = maxval;
  763.            PPM_ASSIGN( *pP, sr, sg, sb );
  764.          }
  765.  
  766.          /* use the assembler subroutine for the colormap search */
  767.          /* this will consume most of the CPU time               */                     
  768.          ind = MapColorASM(colormap, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP),
  769.                            NumColors);
  770.            
  771.          /* compare the results of the ASM versus the C routine */
  772.          /* if they differ the ASM routine has a bug...         */
  773.          /* (we don't need them because they are the same now)  */
  774.          #ifdef DEBUG_ASM
  775.          if(ind != MapColor(colormap, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP),
  776.                             NumColors))
  777.            pm_message("Diff: row %d col %d  r %d g %d b %d\n", row,col,
  778.                        (int)PPM_GETR(*pP), (int)PPM_GETG(*pP), (int)PPM_GETB(*pP));
  779.          #endif
  780.  
  781.          if ( floyd )
  782.          {
  783.            /* Propagate Floyd-Steinberg error terms. */
  784.            if ( fs_direction )
  785.            {
  786.              err = ( sr - (long) PPM_GETR( colormap[ind].color ) ) * FS_SCALE;
  787.              thisrerr[col + 2] += ( err * 7 ) / 16;
  788.              nextrerr[col    ] += ( err * 3 ) / 16;
  789.              nextrerr[col + 1] += ( err * 5 ) / 16;
  790.              nextrerr[col + 2] += ( err     ) / 16;
  791.              err = ( sg - (long) PPM_GETG( colormap[ind].color ) ) * FS_SCALE;
  792.              thisgerr[col + 2] += ( err * 7 ) / 16;
  793.              nextgerr[col    ] += ( err * 3 ) / 16;
  794.              nextgerr[col + 1] += ( err * 5 ) / 16;
  795.              nextgerr[col + 2] += ( err     ) / 16;
  796.              err = ( sb - (long) PPM_GETB( colormap[ind].color ) ) * FS_SCALE;
  797.              thisberr[col + 2] += ( err * 7 ) / 16;
  798.              nextberr[col    ] += ( err * 3 ) / 16;
  799.              nextberr[col + 1] += ( err * 5 ) / 16;
  800.              nextberr[col + 2] += ( err     ) / 16;
  801.            }
  802.            else
  803.            {
  804.              err = ( sr - (long) PPM_GETR( colormap[ind].color ) ) * FS_SCALE;
  805.              thisrerr[col    ] += ( err * 7 ) / 16;
  806.              nextrerr[col + 2] += ( err * 3 ) / 16;
  807.              nextrerr[col + 1] += ( err * 5 ) / 16;
  808.              nextrerr[col    ] += ( err     ) / 16;
  809.              err = ( sg - (long) PPM_GETG( colormap[ind].color ) ) * FS_SCALE;
  810.              thisgerr[col    ] += ( err * 7 ) / 16;
  811.              nextgerr[col + 2] += ( err * 3 ) / 16;
  812.              nextgerr[col + 1] += ( err * 5 ) / 16;
  813.              nextgerr[col    ] += ( err     ) / 16;
  814.              err = ( sb - (long) PPM_GETB( colormap[ind].color ) ) * FS_SCALE;
  815.              thisberr[col    ] += ( err * 7 ) / 16;
  816.              nextberr[col + 2] += ( err * 3 ) / 16;
  817.              nextberr[col + 1] += ( err * 5 ) / 16;
  818.              nextberr[col    ] += ( err     ) / 16;
  819.            }
  820.          }
  821.  
  822.          /* *pP = colormap[ind].color; */
  823.          hamarray[col] = (unsigned char)ind;
  824.  
  825.          if ( ( ! floyd ) || fs_direction )
  826.          {
  827.            ++col;
  828.            ++pP;
  829.          }
  830.          else
  831.          {
  832.            --col;
  833.            --pP;
  834.          }
  835.        }
  836.        while ( col != limitcol );
  837.  
  838.        if ( floyd )
  839.        {
  840.          temperr = thisrerr;
  841.          thisrerr = nextrerr;
  842.          nextrerr = temperr;
  843.          temperr = thisgerr;
  844.          thisgerr = nextgerr;
  845.          nextgerr = temperr;
  846.          temperr = thisberr;
  847.          thisberr = nextberr;
  848.          nextberr = temperr;
  849.          fs_direction = ! fs_direction;
  850.        }
  851.  
  852.        /* ppm_writeppmrow( stdout, pixels[row], cols, maxval, 0 ); */
  853.        /* write one row to the BODY chunk */
  854.        encode_row(hamarray, cols, NumPlanes);
  855.        DisplayRow(hamarray, cols, row);
  856.      }
  857.      IFFError = PopChunk(iff); /* close the BODY */
  858.      if(IFFError) pm_error("Error closing the BODY chunk.\n");
  859.    }       
  860.  }
  861.  
  862.  closeifile((struct ParseInfo *)&ilbm);
  863.  ppmCleanUp();
  864.  return 0;
  865. }
  866.  
  867.  
  868. /* free all resources used by this module */
  869. void ppmCleanUp(void)
  870. {
  871.  CloseDisplay();
  872.  if(colormap) free(colormap);
  873.  if(pgmrow) pgm_freerow(pgmrow); 
  874.  if(coded_rowbuf) free(coded_rowbuf);
  875.  if(CompressBuffer) free(CompressBuffer);
  876.  if(ColorCache) free(ColorCache);
  877.  if(chv) free(chv);
  878.  if(hamarray) free(hamarray);
  879.  if(pixels)
  880.  {
  881.    ppm_freearray(pixels, rows);
  882.  } 
  883.  else
  884.  {
  885.    if(pixrow) pbm_freerow(pixrow);
  886.  }
  887.  if(fppm) fclose(fppm);
  888.  
  889.  if(jpegAGA)
  890.  {
  891.    if(ColorMapFile)
  892.    {
  893.      fclose(ColorMapFile);
  894.      ColorMapFile = NULL;
  895.    }
  896.  }
  897.  else
  898.  {
  899.    if(ilbm.ParseInfo.opened)
  900.    {
  901.      closeifile((struct ParseInfo *)&ilbm);
  902.      remove(ILBMfile);
  903.    }
  904.    if(ilbm.ParseInfo.iff) FreeIFF(ilbm.ParseInfo.iff);
  905.  }
  906. }
  907.  
  908.  
  909.  
  910. /* convert one row from chunky to planar, compress it, */
  911. /* and write it to the BODY chunk                      */
  912.  
  913. /* encode algorithm by Johan Widen (jw@jwdata.se) */
  914. /* modified by Günther Röhrich */
  915.  
  916. const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
  917.  
  918. static void
  919. encode_row(UBYTE *row, int cols, int nPlanes)
  920. {
  921.  register int plane, col;
  922.  int bytes;
  923.  LONG packedRowBytes;
  924.  BYTE *source;
  925.  BYTE *destination;
  926.  
  927.  bytes = RowBytes(cols);
  928.  
  929.  /* Encode and write raw bytes in plane-interleaved form. */
  930.  for( plane = 0; plane < nPlanes; plane++ ) 
  931.  {
  932.    int mask, cbit, wr;
  933.    unsigned char *cp;
  934.    UBYTE *rp;
  935.  
  936.    mask = 1 << plane;
  937.    cbit = -1;
  938.    cp = coded_rowbuf-1;
  939.    rp = row;
  940.    for( col = 0; col < cols; col++, cbit--, rp++ ) 
  941.    {
  942.      if( cbit < 0 ) 
  943.      {
  944.        cbit = 7;
  945.        *++cp = 0;
  946.      }
  947.      if( *rp & mask )
  948.        *cp |= bit_mask[cbit];
  949.    }
  950.    /* wr = fwrite(coded_rowbuf, 1, bytes, stdout); */
  951.  
  952.    /* compress the row */
  953.    source = coded_rowbuf;
  954.    destination = CompressBuffer;
  955.    packedRowBytes = packrow(&source, &destination, bytes);
  956.  
  957.    /* write the compressed row to the BODY chunk */  
  958.    IFFError = WriteChunkBytes(iff, CompressBuffer, packedRowBytes); 
  959.    if(IFFError!=packedRowBytes) pm_error("Error writing BODY chunk.\n");
  960.  }
  961. }
  962.  
  963.  
  964. #ifdef DEBUG_ASM
  965. /* this is the C version of the colormap search routine */
  966. /* (it is now replaced by the ASM version)              */
  967.  
  968. /* search colormap for closest match. */
  969. int MapColor(colorhist_vector colormap, pixval r, pixval g, pixval b, 
  970.              int newcolors)
  971.  int ind;
  972.  register int i, r1, g1, b1, r2, g2, b2;
  973.  register long dist, newdist;
  974.  r1 = r;
  975.  g1 = g;
  976.  b1 = b;
  977.  dist = 2000000000;
  978.  for ( i = 0; i < newcolors; ++i )
  979.  {
  980.    r2 = PPM_GETR( colormap[i].color );
  981.    g2 = PPM_GETG( colormap[i].color );
  982.    b2 = PPM_GETB( colormap[i].color );
  983.    newdist = ( r1 - r2 ) * ( r1 - r2 ) +
  984.              ( g1 - g2 ) * ( g1 - g2 ) +
  985.              ( b1 - b2 ) * ( b1 - b2 );
  986.    if ( newdist < dist )
  987.    {
  988.      ind = i;
  989.      dist = newdist;
  990.    }
  991.  }
  992.  return ind;
  993. }
  994. #endif
  995.  
  996.  
  997.